package services

import (
    "context"
    "io"
    "net/http"

    "github.com/gin-gonic/gin"
    log "github.com/sirupsen/logrus"
    "google.golang.org/protobuf/encoding/protojson"

    "cing.io/cing-api/planner"
    "cing.io/cing-api/task"
    builtins "cing.io/cing/internal/builtins/tasktype"
    "cing.io/cing/internal/clientcache"
    "cing.io/cing/internal/storage"
    "cing.io/cing/pkg/util"
)

var TaskTypeService = &taskTypeService{}

type taskTypeService struct{}

func (*taskTypeService) GetTaskType(ctx *gin.Context) {
    name := ctx.Param("name")
    taskType := storage.GetTaskType(name)
    ctx.JSON(http.StatusOK, taskType)
}

func (*taskTypeService) CreateTaskType(ctx *gin.Context) {
    taskType := &task.TaskType{}
    bytes, _ := io.ReadAll(ctx.Request.Body)
    err := protojson.Unmarshal(bytes, taskType)
    if err != nil {
        ctx.String(http.StatusBadRequest, "Parse error: %s", err.Error())
        return
    }

    has := storage.GetTaskType(taskType.Name)
    if has != nil {
        ctx.String(http.StatusBadRequest, "The TaskType %s is existing!", taskType.Name)
        return
    }

    echoAndStoreTaskType(ctx, taskType)
}

func (*taskTypeService) UpdateTaskType(ctx *gin.Context) {
    taskType := &task.TaskType{}
    bytes, _ := io.ReadAll(ctx.Request.Body)
    err := protojson.Unmarshal(bytes, taskType)
    if err != nil {
        log.Error(err)
    }

    has := builtins.GetTaskType(taskType.Name)
    if has != nil {
        ctx.String(http.StatusBadRequest, "The TaskType %s is builtin!", taskType.Name)
        return
    }

    has = storage.GetTaskType(taskType.Name)
    if has == nil {
        ctx.String(http.StatusBadRequest, "The TaskType %s is not exist!", taskType.Name)
        return
    }

    echoAndStoreTaskType(ctx, taskType)
}

func echoAndStoreTaskType(ctx *gin.Context, taskType *task.TaskType) {
    namespace, service := util.SplitNamespaceAndName(taskType.PlannerService)
    cli, err := clientcache.Planner.GetPlannerInService(namespace, service)
    if err != nil || cli == nil {
        ctx.String(http.StatusBadRequest, "Dial PlannerService error: %s", err.Error())
        return
    }

    resp, err := cli.TaskTypeEcho(context.TODO(), &planner.TaskTypeEchoRequest{TaskTypeName: taskType.Name})
    if err != nil {
        ctx.String(http.StatusBadRequest, "RPC error: %s", err.Error())
        return
    }

    if !resp.Ok {
        ctx.String(http.StatusBadRequest, "PlannerService %s reject the TaskType %s", taskType.PlannerService, taskType.Name)
        return
    }

    if resp.TaskType != nil {
        taskType = resp.TaskType
    }
    err = storage.PutTaskType(taskType)
    if err != nil {
        ctx.String(http.StatusBadRequest, "Store error: %s", err.Error())
        return
    }

    ctx.JSON(http.StatusOK, gin.H{
        "code": http.StatusOK,
        "data": gin.H{
            "taskType": taskType,
        },
    })
}

func (*taskTypeService) DeleteTaskType(ctx *gin.Context) {
    name := ctx.Param("name")
    builtin := builtins.GetTaskType(name)
    if builtin != nil {
        ctx.String(http.StatusBadRequest, "The TaskType %s is builtin!", name)
        return
    }

    taskType := storage.GetTaskType(name)
    if taskType == nil {
        ctx.String(http.StatusBadRequest, "The TaskType %s is not exist!", name)
    }

    err := storage.DeleteTaskType(name)
    if err != nil {
        ctx.String(http.StatusBadRequest, "Delete error: ", err.Error())
        return
    }
    ctx.Status(http.StatusOK)
}
